OLD | NEW |
| (Empty) |
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. | |
4 | |
5 #include "config.h" | |
6 | |
7 #include "CCThreadProxy.h" | |
8 | |
9 #include "CCDelayBasedTimeSource.h" | |
10 #include "CCDrawQuad.h" | |
11 #include "CCFrameRateController.h" | |
12 #include "CCGraphicsContext.h" | |
13 #include "CCInputHandler.h" | |
14 #include "CCLayerTreeHost.h" | |
15 #include "CCScheduler.h" | |
16 #include "CCScopedThreadProxy.h" | |
17 #include "CCThreadTask.h" | |
18 #include "TraceEvent.h" | |
19 #include <public/WebSharedGraphicsContext3D.h> | |
20 #include <wtf/CurrentTime.h> | |
21 | |
22 using namespace WTF; | |
23 using WebKit::WebSharedGraphicsContext3D; | |
24 | |
25 namespace { | |
26 | |
27 // Measured in seconds. | |
28 const double contextRecreationTickRate = 0.03; | |
29 | |
30 } // namespace | |
31 | |
32 namespace cc { | |
33 | |
34 scoped_ptr<CCProxy> CCThreadProxy::create(CCLayerTreeHost* layerTreeHost) | |
35 { | |
36 return make_scoped_ptr(new CCThreadProxy(layerTreeHost)).PassAs<CCProxy>(); | |
37 } | |
38 | |
39 CCThreadProxy::CCThreadProxy(CCLayerTreeHost* layerTreeHost) | |
40 : m_animateRequested(false) | |
41 , m_commitRequested(false) | |
42 , m_commitRequestSentToImplThread(false) | |
43 , m_forcedCommitRequested(false) | |
44 , m_layerTreeHost(layerTreeHost) | |
45 , m_rendererInitialized(false) | |
46 , m_started(false) | |
47 , m_texturesAcquired(true) | |
48 , m_inCompositeAndReadback(false) | |
49 , m_mainThreadProxy(CCScopedThreadProxy::create(CCProxy::mainThread())) | |
50 , m_beginFrameCompletionEventOnImplThread(0) | |
51 , m_readbackRequestOnImplThread(0) | |
52 , m_commitCompletionEventOnImplThread(0) | |
53 , m_textureAcquisitionCompletionEventOnImplThread(0) | |
54 , m_resetContentsTexturesPurgedAfterCommitOnImplThread(false) | |
55 , m_nextFrameIsNewlyCommittedFrameOnImplThread(false) | |
56 , m_renderVSyncEnabled(layerTreeHost->settings().renderVSyncEnabled) | |
57 , m_totalCommitCount(0) | |
58 { | |
59 TRACE_EVENT0("cc", "CCThreadProxy::CCThreadProxy"); | |
60 ASSERT(isMainThread()); | |
61 } | |
62 | |
63 CCThreadProxy::~CCThreadProxy() | |
64 { | |
65 TRACE_EVENT0("cc", "CCThreadProxy::~CCThreadProxy"); | |
66 ASSERT(isMainThread()); | |
67 ASSERT(!m_started); | |
68 } | |
69 | |
70 bool CCThreadProxy::compositeAndReadback(void *pixels, const IntRect& rect) | |
71 { | |
72 TRACE_EVENT0("cc", "CCThreadPRoxy::compositeAndReadback"); | |
73 ASSERT(isMainThread()); | |
74 ASSERT(m_layerTreeHost); | |
75 | |
76 if (!m_layerTreeHost->initializeRendererIfNeeded()) { | |
77 TRACE_EVENT0("cc", "compositeAndReadback_EarlyOut_LR_Uninitialized"); | |
78 return false; | |
79 } | |
80 | |
81 | |
82 // Perform a synchronous commit. | |
83 { | |
84 DebugScopedSetMainThreadBlocked mainThreadBlocked; | |
85 CCCompletionEvent beginFrameCompletion; | |
86 CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy:
:forceBeginFrameOnImplThread, &beginFrameCompletion)); | |
87 beginFrameCompletion.wait(); | |
88 } | |
89 m_inCompositeAndReadback = true; | |
90 beginFrame(); | |
91 m_inCompositeAndReadback = false; | |
92 | |
93 // Perform a synchronous readback. | |
94 ReadbackRequest request; | |
95 request.rect = rect; | |
96 request.pixels = pixels; | |
97 { | |
98 DebugScopedSetMainThreadBlocked mainThreadBlocked; | |
99 CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy:
:requestReadbackOnImplThread, &request)); | |
100 request.completion.wait(); | |
101 } | |
102 return request.success; | |
103 } | |
104 | |
105 void CCThreadProxy::requestReadbackOnImplThread(ReadbackRequest* request) | |
106 { | |
107 ASSERT(CCProxy::isImplThread()); | |
108 ASSERT(!m_readbackRequestOnImplThread); | |
109 if (!m_layerTreeHostImpl.get()) { | |
110 request->success = false; | |
111 request->completion.signal(); | |
112 return; | |
113 } | |
114 | |
115 m_readbackRequestOnImplThread = request; | |
116 m_schedulerOnImplThread->setNeedsRedraw(); | |
117 m_schedulerOnImplThread->setNeedsForcedRedraw(); | |
118 } | |
119 | |
120 void CCThreadProxy::startPageScaleAnimation(const IntSize& targetPosition, bool
useAnchor, float scale, double duration) | |
121 { | |
122 ASSERT(CCProxy::isMainThread()); | |
123 CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy::req
uestStartPageScaleAnimationOnImplThread, targetPosition, useAnchor, scale, durat
ion)); | |
124 } | |
125 | |
126 void CCThreadProxy::requestStartPageScaleAnimationOnImplThread(IntSize targetPos
ition, bool useAnchor, float scale, double duration) | |
127 { | |
128 ASSERT(CCProxy::isImplThread()); | |
129 if (m_layerTreeHostImpl.get()) | |
130 m_layerTreeHostImpl->startPageScaleAnimation(targetPosition, useAnchor,
scale, monotonicallyIncreasingTime(), duration); | |
131 } | |
132 | |
133 void CCThreadProxy::finishAllRendering() | |
134 { | |
135 ASSERT(CCProxy::isMainThread()); | |
136 | |
137 // Make sure all GL drawing is finished on the impl thread. | |
138 DebugScopedSetMainThreadBlocked mainThreadBlocked; | |
139 CCCompletionEvent completion; | |
140 CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy::fin
ishAllRenderingOnImplThread, &completion)); | |
141 completion.wait(); | |
142 } | |
143 | |
144 bool CCThreadProxy::isStarted() const | |
145 { | |
146 ASSERT(CCProxy::isMainThread()); | |
147 return m_started; | |
148 } | |
149 | |
150 bool CCThreadProxy::initializeContext() | |
151 { | |
152 TRACE_EVENT0("cc", "CCThreadProxy::initializeContext"); | |
153 scoped_ptr<CCGraphicsContext> context = m_layerTreeHost->createContext(); | |
154 if (!context.get()) | |
155 return false; | |
156 | |
157 CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy::ini
tializeContextOnImplThread, | |
158 context.release())); | |
159 return true; | |
160 } | |
161 | |
162 void CCThreadProxy::setSurfaceReady() | |
163 { | |
164 TRACE_EVENT0("cc", "CCThreadProxy::setSurfaceReady"); | |
165 CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy::set
SurfaceReadyOnImplThread)); | |
166 } | |
167 | |
168 void CCThreadProxy::setSurfaceReadyOnImplThread() | |
169 { | |
170 TRACE_EVENT0("cc", "CCThreadProxy::setSurfaceReadyOnImplThread"); | |
171 m_schedulerOnImplThread->setCanBeginFrame(true); | |
172 } | |
173 | |
174 void CCThreadProxy::setVisible(bool visible) | |
175 { | |
176 TRACE_EVENT0("cc", "CCThreadProxy::setVisible"); | |
177 DebugScopedSetMainThreadBlocked mainThreadBlocked; | |
178 CCCompletionEvent completion; | |
179 CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy::set
VisibleOnImplThread, &completion, visible)); | |
180 completion.wait(); | |
181 } | |
182 | |
183 void CCThreadProxy::setVisibleOnImplThread(CCCompletionEvent* completion, bool v
isible) | |
184 { | |
185 TRACE_EVENT0("cc", "CCThreadProxy::setVisibleOnImplThread"); | |
186 m_layerTreeHostImpl->setVisible(visible); | |
187 m_schedulerOnImplThread->setVisible(visible); | |
188 completion->signal(); | |
189 } | |
190 | |
191 bool CCThreadProxy::initializeRenderer() | |
192 { | |
193 TRACE_EVENT0("cc", "CCThreadProxy::initializeRenderer"); | |
194 // Make a blocking call to initializeRendererOnImplThread. The results of th
at call | |
195 // are pushed into the initializeSucceeded and capabilities local variables. | |
196 CCCompletionEvent completion; | |
197 bool initializeSucceeded = false; | |
198 RendererCapabilities capabilities; | |
199 DebugScopedSetMainThreadBlocked mainThreadBlocked; | |
200 CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy::ini
tializeRendererOnImplThread, | |
201 &completion, | |
202 &initializeSucceeded, | |
203 &capabilities)); | |
204 completion.wait(); | |
205 | |
206 if (initializeSucceeded) { | |
207 m_rendererInitialized = true; | |
208 m_RendererCapabilitiesMainThreadCopy = capabilities; | |
209 } | |
210 return initializeSucceeded; | |
211 } | |
212 | |
213 bool CCThreadProxy::recreateContext() | |
214 { | |
215 TRACE_EVENT0("cc", "CCThreadProxy::recreateContext"); | |
216 ASSERT(isMainThread()); | |
217 | |
218 // Try to create the context. | |
219 scoped_ptr<CCGraphicsContext> context = m_layerTreeHost->createContext(); | |
220 if (!context.get()) | |
221 return false; | |
222 if (m_layerTreeHost->needsSharedContext()) | |
223 if (!WebSharedGraphicsContext3D::createCompositorThreadContext()) | |
224 return false; | |
225 | |
226 // Make a blocking call to recreateContextOnImplThread. The results of that | |
227 // call are pushed into the recreateSucceeded and capabilities local | |
228 // variables. | |
229 CCCompletionEvent completion; | |
230 bool recreateSucceeded = false; | |
231 RendererCapabilities capabilities; | |
232 DebugScopedSetMainThreadBlocked mainThreadBlocked; | |
233 CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy::rec
reateContextOnImplThread, | |
234 &completion, | |
235 context.release(), | |
236 &recreateSucceeded, | |
237 &capabilities)); | |
238 completion.wait(); | |
239 | |
240 if (recreateSucceeded) | |
241 m_RendererCapabilitiesMainThreadCopy = capabilities; | |
242 return recreateSucceeded; | |
243 } | |
244 | |
245 void CCThreadProxy::renderingStats(CCRenderingStats* stats) | |
246 { | |
247 ASSERT(isMainThread()); | |
248 | |
249 DebugScopedSetMainThreadBlocked mainThreadBlocked; | |
250 CCCompletionEvent completion; | |
251 CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy::ren
deringStatsOnImplThread, | |
252 &completion, | |
253 stats)); | |
254 stats->totalCommitTimeInSeconds = m_totalCommitTime.InSecondsF(); | |
255 stats->totalCommitCount = m_totalCommitCount; | |
256 | |
257 completion.wait(); | |
258 } | |
259 | |
260 const RendererCapabilities& CCThreadProxy::rendererCapabilities() const | |
261 { | |
262 ASSERT(m_rendererInitialized); | |
263 return m_RendererCapabilitiesMainThreadCopy; | |
264 } | |
265 | |
266 void CCThreadProxy::loseContext() | |
267 { | |
268 CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy::did
LoseContextOnImplThread)); | |
269 } | |
270 | |
271 void CCThreadProxy::setNeedsAnimate() | |
272 { | |
273 ASSERT(isMainThread()); | |
274 if (m_animateRequested) | |
275 return; | |
276 | |
277 TRACE_EVENT0("cc", "CCThreadProxy::setNeedsAnimate"); | |
278 m_animateRequested = true; | |
279 | |
280 if (m_commitRequestSentToImplThread) | |
281 return; | |
282 m_commitRequestSentToImplThread = true; | |
283 CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy::set
NeedsCommitOnImplThread)); | |
284 } | |
285 | |
286 void CCThreadProxy::setNeedsCommit() | |
287 { | |
288 ASSERT(isMainThread()); | |
289 if (m_commitRequested) | |
290 return; | |
291 TRACE_EVENT0("cc", "CCThreadProxy::setNeedsCommit"); | |
292 m_commitRequested = true; | |
293 | |
294 if (m_commitRequestSentToImplThread) | |
295 return; | |
296 m_commitRequestSentToImplThread = true; | |
297 CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy::set
NeedsCommitOnImplThread)); | |
298 } | |
299 | |
300 void CCThreadProxy::didLoseContextOnImplThread() | |
301 { | |
302 ASSERT(isImplThread()); | |
303 TRACE_EVENT0("cc", "CCThreadProxy::didLoseContextOnImplThread"); | |
304 m_schedulerOnImplThread->didLoseContext(); | |
305 } | |
306 | |
307 void CCThreadProxy::onSwapBuffersCompleteOnImplThread() | |
308 { | |
309 ASSERT(isImplThread()); | |
310 TRACE_EVENT0("cc", "CCThreadProxy::onSwapBuffersCompleteOnImplThread"); | |
311 m_schedulerOnImplThread->didSwapBuffersComplete(); | |
312 m_mainThreadProxy->postTask(createCCThreadTask(this, &CCThreadProxy::didComp
leteSwapBuffers)); | |
313 } | |
314 | |
315 void CCThreadProxy::onVSyncParametersChanged(double monotonicTimebase, double in
tervalInSeconds) | |
316 { | |
317 ASSERT(isImplThread()); | |
318 TRACE_EVENT2("cc", "CCThreadProxy::onVSyncParametersChanged", "monotonicTime
base", monotonicTimebase, "intervalInSeconds", intervalInSeconds); | |
319 base::TimeTicks timebase = base::TimeTicks::FromInternalValue(monotonicTimeb
ase * base::Time::kMicrosecondsPerSecond); | |
320 base::TimeDelta interval = base::TimeDelta::FromMicroseconds(intervalInSecon
ds * base::Time::kMicrosecondsPerSecond); | |
321 m_schedulerOnImplThread->setTimebaseAndInterval(timebase, interval); | |
322 } | |
323 | |
324 void CCThreadProxy::onCanDrawStateChanged(bool canDraw) | |
325 { | |
326 ASSERT(isImplThread()); | |
327 TRACE_EVENT1("cc", "CCThreadProxy::onCanDrawStateChanged", "canDraw", canDra
w); | |
328 m_schedulerOnImplThread->setCanDraw(canDraw); | |
329 } | |
330 | |
331 void CCThreadProxy::setNeedsCommitOnImplThread() | |
332 { | |
333 ASSERT(isImplThread()); | |
334 TRACE_EVENT0("cc", "CCThreadProxy::setNeedsCommitOnImplThread"); | |
335 m_schedulerOnImplThread->setNeedsCommit(); | |
336 } | |
337 | |
338 void CCThreadProxy::setNeedsForcedCommitOnImplThread() | |
339 { | |
340 ASSERT(isImplThread()); | |
341 TRACE_EVENT0("cc", "CCThreadProxy::setNeedsForcedCommitOnImplThread"); | |
342 m_schedulerOnImplThread->setNeedsCommit(); | |
343 m_schedulerOnImplThread->setNeedsForcedCommit(); | |
344 } | |
345 | |
346 void CCThreadProxy::postAnimationEventsToMainThreadOnImplThread(scoped_ptr<CCAni
mationEventsVector> events, double wallClockTime) | |
347 { | |
348 ASSERT(isImplThread()); | |
349 TRACE_EVENT0("cc", "CCThreadProxy::postAnimationEventsToMainThreadOnImplThre
ad"); | |
350 m_mainThreadProxy->postTask(createCCThreadTask(this, &CCThreadProxy::setAnim
ationEvents, events.release(), wallClockTime)); | |
351 } | |
352 | |
353 void CCThreadProxy::releaseContentsTexturesOnImplThread() | |
354 { | |
355 ASSERT(isImplThread()); | |
356 | |
357 m_layerTreeHost->reduceContentsTexturesMemoryOnImplThread(0, m_layerTreeHost
Impl->resourceProvider()); | |
358 | |
359 // Make sure that we get a new commit before drawing again. | |
360 m_resetContentsTexturesPurgedAfterCommitOnImplThread = false; | |
361 // The texture upload queue may reference textures that were just purged, cl
ear | |
362 // them from the queue. | |
363 if (m_currentTextureUpdateControllerOnImplThread.get() && m_layerTreeHost->e
victedContentsTexturesBackingsExist()) | |
364 m_currentTextureUpdateControllerOnImplThread->discardUploadsToEvictedRes
ources(); | |
365 } | |
366 | |
367 void CCThreadProxy::setNeedsRedraw() | |
368 { | |
369 ASSERT(isMainThread()); | |
370 TRACE_EVENT0("cc", "CCThreadProxy::setNeedsRedraw"); | |
371 CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy::set
FullRootLayerDamageOnImplThread)); | |
372 CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy::set
NeedsRedrawOnImplThread)); | |
373 } | |
374 | |
375 bool CCThreadProxy::commitRequested() const | |
376 { | |
377 ASSERT(isMainThread()); | |
378 return m_commitRequested; | |
379 } | |
380 | |
381 void CCThreadProxy::setNeedsRedrawOnImplThread() | |
382 { | |
383 ASSERT(isImplThread()); | |
384 TRACE_EVENT0("cc", "CCThreadProxy::setNeedsRedrawOnImplThread"); | |
385 m_schedulerOnImplThread->setNeedsRedraw(); | |
386 } | |
387 | |
388 void CCThreadProxy::start() | |
389 { | |
390 ASSERT(isMainThread()); | |
391 ASSERT(CCProxy::implThread()); | |
392 // Create LayerTreeHostImpl. | |
393 DebugScopedSetMainThreadBlocked mainThreadBlocked; | |
394 CCCompletionEvent completion; | |
395 scoped_ptr<CCInputHandler> handler = m_layerTreeHost->createInputHandler(); | |
396 CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy::ini
tializeImplOnImplThread, &completion, handler.release())); | |
397 completion.wait(); | |
398 | |
399 m_started = true; | |
400 } | |
401 | |
402 void CCThreadProxy::stop() | |
403 { | |
404 TRACE_EVENT0("cc", "CCThreadProxy::stop"); | |
405 ASSERT(isMainThread()); | |
406 ASSERT(m_started); | |
407 | |
408 // Synchronously deletes the impl. | |
409 { | |
410 DebugScopedSetMainThreadBlocked mainThreadBlocked; | |
411 | |
412 CCCompletionEvent completion; | |
413 CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy:
:layerTreeHostClosedOnImplThread, &completion)); | |
414 completion.wait(); | |
415 } | |
416 | |
417 m_mainThreadProxy->shutdown(); // Stop running tasks posted to us. | |
418 | |
419 ASSERT(!m_layerTreeHostImpl.get()); // verify that the impl deleted. | |
420 m_layerTreeHost = 0; | |
421 m_started = false; | |
422 } | |
423 | |
424 void CCThreadProxy::forceSerializeOnSwapBuffers() | |
425 { | |
426 DebugScopedSetMainThreadBlocked mainThreadBlocked; | |
427 CCCompletionEvent completion; | |
428 CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy::for
ceSerializeOnSwapBuffersOnImplThread, &completion)); | |
429 completion.wait(); | |
430 } | |
431 | |
432 void CCThreadProxy::forceSerializeOnSwapBuffersOnImplThread(CCCompletionEvent* c
ompletion) | |
433 { | |
434 if (m_rendererInitialized) | |
435 m_layerTreeHostImpl->renderer()->doNoOp(); | |
436 completion->signal(); | |
437 } | |
438 | |
439 | |
440 void CCThreadProxy::finishAllRenderingOnImplThread(CCCompletionEvent* completion
) | |
441 { | |
442 TRACE_EVENT0("cc", "CCThreadProxy::finishAllRenderingOnImplThread"); | |
443 ASSERT(isImplThread()); | |
444 m_layerTreeHostImpl->finishAllRendering(); | |
445 completion->signal(); | |
446 } | |
447 | |
448 void CCThreadProxy::forceBeginFrameOnImplThread(CCCompletionEvent* completion) | |
449 { | |
450 TRACE_EVENT0("cc", "CCThreadProxy::forceBeginFrameOnImplThread"); | |
451 ASSERT(!m_beginFrameCompletionEventOnImplThread); | |
452 | |
453 if (m_schedulerOnImplThread->commitPending()) { | |
454 completion->signal(); | |
455 return; | |
456 } | |
457 | |
458 m_beginFrameCompletionEventOnImplThread = completion; | |
459 setNeedsForcedCommitOnImplThread(); | |
460 } | |
461 | |
462 void CCThreadProxy::scheduledActionBeginFrame() | |
463 { | |
464 TRACE_EVENT0("cc", "CCThreadProxy::scheduledActionBeginFrame"); | |
465 ASSERT(!m_pendingBeginFrameRequest); | |
466 m_pendingBeginFrameRequest = adoptPtr(new BeginFrameAndCommitState()); | |
467 m_pendingBeginFrameRequest->monotonicFrameBeginTime = monotonicallyIncreasin
gTime(); | |
468 m_pendingBeginFrameRequest->scrollInfo = m_layerTreeHostImpl->processScrollD
eltas(); | |
469 m_pendingBeginFrameRequest->implTransform = m_layerTreeHostImpl->implTransfo
rm(); | |
470 m_pendingBeginFrameRequest->memoryAllocationLimitBytes = m_layerTreeHostImpl
->memoryAllocationLimitBytes(); | |
471 m_layerTreeHost->getEvictedContentTexturesBackings(m_pendingBeginFrameReques
t->evictedContentsTexturesBackings); | |
472 | |
473 m_mainThreadProxy->postTask(createCCThreadTask(this, &CCThreadProxy::beginFr
ame)); | |
474 | |
475 if (m_beginFrameCompletionEventOnImplThread) { | |
476 m_beginFrameCompletionEventOnImplThread->signal(); | |
477 m_beginFrameCompletionEventOnImplThread = 0; | |
478 } | |
479 } | |
480 | |
481 void CCThreadProxy::beginFrame() | |
482 { | |
483 TRACE_EVENT0("cc", "CCThreadProxy::beginFrame"); | |
484 ASSERT(isMainThread()); | |
485 if (!m_layerTreeHost) | |
486 return; | |
487 | |
488 if (!m_pendingBeginFrameRequest) { | |
489 TRACE_EVENT0("cc", "EarlyOut_StaleBeginFrameMessage"); | |
490 return; | |
491 } | |
492 | |
493 if (m_layerTreeHost->needsSharedContext() && !WebSharedGraphicsContext3D::ha
veCompositorThreadContext()) | |
494 WebSharedGraphicsContext3D::createCompositorThreadContext(); | |
495 | |
496 OwnPtr<BeginFrameAndCommitState> request(m_pendingBeginFrameRequest.release(
)); | |
497 | |
498 // Do not notify the impl thread of commit requests that occur during | |
499 // the apply/animate/layout part of the beginFrameAndCommit process since | |
500 // those commit requests will get painted immediately. Once we have done | |
501 // the paint, m_commitRequested will be set to false to allow new commit | |
502 // requests to be scheduled. | |
503 m_commitRequested = true; | |
504 m_commitRequestSentToImplThread = true; | |
505 | |
506 // On the other hand, the animationRequested flag needs to be cleared | |
507 // here so that any animation requests generated by the apply or animate | |
508 // callbacks will trigger another frame. | |
509 m_animateRequested = false; | |
510 | |
511 // FIXME: technically, scroll deltas need to be applied for dropped commits
as well. | |
512 // Re-do the commit flow so that we don't send the scrollInfo on the BFAC me
ssage. | |
513 m_layerTreeHost->applyScrollAndScale(*request->scrollInfo); | |
514 m_layerTreeHost->setImplTransform(request->implTransform); | |
515 | |
516 if (!m_inCompositeAndReadback && !m_layerTreeHost->visible()) { | |
517 m_commitRequested = false; | |
518 m_commitRequestSentToImplThread = false; | |
519 m_forcedCommitRequested = false; | |
520 | |
521 TRACE_EVENT0("cc", "EarlyOut_NotVisible"); | |
522 CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy:
:beginFrameAbortedOnImplThread)); | |
523 return; | |
524 } | |
525 | |
526 m_layerTreeHost->willBeginFrame(); | |
527 | |
528 m_layerTreeHost->updateAnimations(request->monotonicFrameBeginTime); | |
529 m_layerTreeHost->layout(); | |
530 | |
531 // Clear the commit flag after updating animations and layout here --- objec
ts that only | |
532 // layout when painted will trigger another setNeedsCommit inside | |
533 // updateLayers. | |
534 m_commitRequested = false; | |
535 m_commitRequestSentToImplThread = false; | |
536 m_forcedCommitRequested = false; | |
537 | |
538 if (!m_layerTreeHost->initializeRendererIfNeeded()) { | |
539 TRACE_EVENT0("cc", "EarlyOut_InitializeFailed"); | |
540 return; | |
541 } | |
542 | |
543 m_layerTreeHost->unlinkEvictedContentTexturesBackings(request->evictedConten
tsTexturesBackings); | |
544 | |
545 OwnPtr<CCTextureUpdateQueue> queue = adoptPtr(new CCTextureUpdateQueue); | |
546 m_layerTreeHost->updateLayers(*(queue.get()), request->memoryAllocationLimit
Bytes); | |
547 | |
548 // Once single buffered layers are committed, they cannot be modified until | |
549 // they are drawn by the impl thread. | |
550 m_texturesAcquired = false; | |
551 | |
552 m_layerTreeHost->willCommit(); | |
553 // Before applying scrolls and calling animate, we set m_animateRequested to | |
554 // false. If it is true now, it means setNeedAnimate was called again, but | |
555 // during a state when m_commitRequestSentToImplThread = true. We need to | |
556 // force that call to happen again now so that the commit request is sent to | |
557 // the impl thread. | |
558 if (m_animateRequested) { | |
559 // Forces setNeedsAnimate to consider posting a commit task. | |
560 m_animateRequested = false; | |
561 setNeedsAnimate(); | |
562 } | |
563 | |
564 // Notify the impl thread that the beginFrame has completed. This will | |
565 // begin the commit process, which is blocking from the main thread's | |
566 // point of view, but asynchronously performed on the impl thread, | |
567 // coordinated by the CCScheduler. | |
568 { | |
569 TRACE_EVENT0("cc", "commit"); | |
570 | |
571 DebugScopedSetMainThreadBlocked mainThreadBlocked; | |
572 | |
573 base::TimeTicks startTime = base::TimeTicks::HighResNow(); | |
574 CCCompletionEvent completion; | |
575 CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy:
:beginFrameCompleteOnImplThread, &completion, queue.release())); | |
576 completion.wait(); | |
577 base::TimeTicks endTime = base::TimeTicks::HighResNow(); | |
578 | |
579 m_totalCommitTime += endTime - startTime; | |
580 m_totalCommitCount++; | |
581 } | |
582 | |
583 m_layerTreeHost->commitComplete(); | |
584 m_layerTreeHost->didBeginFrame(); | |
585 } | |
586 | |
587 void CCThreadProxy::beginFrameCompleteOnImplThread(CCCompletionEvent* completion
, PassOwnPtr<CCTextureUpdateQueue> queue) | |
588 { | |
589 TRACE_EVENT0("cc", "CCThreadProxy::beginFrameCompleteOnImplThread"); | |
590 ASSERT(!m_commitCompletionEventOnImplThread); | |
591 ASSERT(isImplThread() && isMainThreadBlocked()); | |
592 ASSERT(m_schedulerOnImplThread); | |
593 ASSERT(m_schedulerOnImplThread->commitPending()); | |
594 | |
595 if (!m_layerTreeHostImpl.get()) { | |
596 TRACE_EVENT0("cc", "EarlyOut_NoLayerTree"); | |
597 completion->signal(); | |
598 return; | |
599 } | |
600 | |
601 // Clear any uploads we were making to textures linked to evicted | |
602 // resources | |
603 if (m_layerTreeHost->evictedContentsTexturesBackingsExist()) | |
604 queue->clearUploadsToEvictedResources(); | |
605 | |
606 // If we unlinked evicted textures on the main thread, delete them now. | |
607 if (m_layerTreeHost->deleteEvictedContentTexturesBackings()) { | |
608 // Deleting the evicted textures' backings resulted in some textures in
the | |
609 // layer tree being invalidated (unliked from their backings). Kick off | |
610 // another commit to fill them again. | |
611 setNeedsCommitOnImplThread(); | |
612 } else { | |
613 // The layer tree does not reference evicted textures, so mark that we | |
614 // can draw this tree once this commit is complete. | |
615 if (m_layerTreeHostImpl->contentsTexturesPurged()) | |
616 m_resetContentsTexturesPurgedAfterCommitOnImplThread = true; | |
617 } | |
618 | |
619 m_currentTextureUpdateControllerOnImplThread = CCTextureUpdateController::cr
eate(this, CCProxy::implThread(), queue, m_layerTreeHostImpl->resourceProvider()
, m_layerTreeHostImpl->resourceProvider()->textureUploader()); | |
620 m_currentTextureUpdateControllerOnImplThread->performMoreUpdates( | |
621 m_schedulerOnImplThread->anticipatedDrawTime()); | |
622 | |
623 m_commitCompletionEventOnImplThread = completion; | |
624 } | |
625 | |
626 void CCThreadProxy::beginFrameAbortedOnImplThread() | |
627 { | |
628 TRACE_EVENT0("cc", "CCThreadProxy::beginFrameAbortedOnImplThread"); | |
629 ASSERT(isImplThread()); | |
630 ASSERT(m_schedulerOnImplThread); | |
631 ASSERT(m_schedulerOnImplThread->commitPending()); | |
632 | |
633 m_schedulerOnImplThread->beginFrameAborted(); | |
634 } | |
635 | |
636 void CCThreadProxy::scheduledActionCommit() | |
637 { | |
638 TRACE_EVENT0("cc", "CCThreadProxy::scheduledActionCommit"); | |
639 ASSERT(isImplThread()); | |
640 ASSERT(m_commitCompletionEventOnImplThread); | |
641 ASSERT(m_currentTextureUpdateControllerOnImplThread); | |
642 | |
643 // Complete all remaining texture updates. | |
644 m_currentTextureUpdateControllerOnImplThread->finalize(); | |
645 m_currentTextureUpdateControllerOnImplThread.clear(); | |
646 | |
647 m_layerTreeHostImpl->beginCommit(); | |
648 | |
649 m_layerTreeHost->beginCommitOnImplThread(m_layerTreeHostImpl.get()); | |
650 m_layerTreeHost->finishCommitOnImplThread(m_layerTreeHostImpl.get()); | |
651 | |
652 if (m_resetContentsTexturesPurgedAfterCommitOnImplThread) { | |
653 m_resetContentsTexturesPurgedAfterCommitOnImplThread = false; | |
654 m_layerTreeHostImpl->resetContentsTexturesPurged(); | |
655 } | |
656 | |
657 m_layerTreeHostImpl->commitComplete(); | |
658 | |
659 m_nextFrameIsNewlyCommittedFrameOnImplThread = true; | |
660 | |
661 m_commitCompletionEventOnImplThread->signal(); | |
662 m_commitCompletionEventOnImplThread = 0; | |
663 | |
664 // SetVisible kicks off the next scheduler action, so this must be last. | |
665 m_schedulerOnImplThread->setVisible(m_layerTreeHostImpl->visible()); | |
666 } | |
667 | |
668 void CCThreadProxy::scheduledActionBeginContextRecreation() | |
669 { | |
670 ASSERT(isImplThread()); | |
671 m_mainThreadProxy->postTask(createCCThreadTask(this, &CCThreadProxy::beginCo
ntextRecreation)); | |
672 } | |
673 | |
674 CCScheduledActionDrawAndSwapResult CCThreadProxy::scheduledActionDrawAndSwapInte
rnal(bool forcedDraw) | |
675 { | |
676 TRACE_EVENT0("cc", "CCThreadProxy::scheduledActionDrawAndSwap"); | |
677 CCScheduledActionDrawAndSwapResult result; | |
678 result.didDraw = false; | |
679 result.didSwap = false; | |
680 ASSERT(isImplThread()); | |
681 ASSERT(m_layerTreeHostImpl.get()); | |
682 if (!m_layerTreeHostImpl.get()) | |
683 return result; | |
684 | |
685 ASSERT(m_layerTreeHostImpl->renderer()); | |
686 if (!m_layerTreeHostImpl->renderer()) | |
687 return result; | |
688 | |
689 // FIXME: compute the frame display time more intelligently | |
690 double monotonicTime = monotonicallyIncreasingTime(); | |
691 double wallClockTime = currentTime(); | |
692 | |
693 if (m_inputHandlerOnImplThread.get()) | |
694 m_inputHandlerOnImplThread->animate(monotonicTime); | |
695 m_layerTreeHostImpl->animate(monotonicTime, wallClockTime); | |
696 | |
697 // This method is called on a forced draw, regardless of whether we are able
to produce a frame, | |
698 // as the calling site on main thread is blocked until its request completes
, and we signal | |
699 // completion here. If canDraw() is false, we will indicate success=false to
the caller, but we | |
700 // must still signal completion to avoid deadlock. | |
701 | |
702 // We guard prepareToDraw() with canDraw() because it always returns a valid
frame, so can only | |
703 // be used when such a frame is possible. Since drawLayers() depends on the
result of | |
704 // prepareToDraw(), it is guarded on canDraw() as well. | |
705 | |
706 CCLayerTreeHostImpl::FrameData frame; | |
707 bool drawFrame = m_layerTreeHostImpl->canDraw() && (m_layerTreeHostImpl->pre
pareToDraw(frame) || forcedDraw); | |
708 if (drawFrame) { | |
709 m_layerTreeHostImpl->drawLayers(frame); | |
710 result.didDraw = true; | |
711 } | |
712 m_layerTreeHostImpl->didDrawAllLayers(frame); | |
713 | |
714 // Check for a pending compositeAndReadback. | |
715 if (m_readbackRequestOnImplThread) { | |
716 m_readbackRequestOnImplThread->success = false; | |
717 if (drawFrame) { | |
718 m_layerTreeHostImpl->readback(m_readbackRequestOnImplThread->pixels,
m_readbackRequestOnImplThread->rect); | |
719 m_readbackRequestOnImplThread->success = !m_layerTreeHostImpl->isCon
textLost(); | |
720 } | |
721 m_readbackRequestOnImplThread->completion.signal(); | |
722 m_readbackRequestOnImplThread = 0; | |
723 } else if (drawFrame) | |
724 result.didSwap = m_layerTreeHostImpl->swapBuffers(); | |
725 | |
726 // Tell the main thread that the the newly-commited frame was drawn. | |
727 if (m_nextFrameIsNewlyCommittedFrameOnImplThread) { | |
728 m_nextFrameIsNewlyCommittedFrameOnImplThread = false; | |
729 m_mainThreadProxy->postTask(createCCThreadTask(this, &CCThreadProxy::did
CommitAndDrawFrame)); | |
730 } | |
731 | |
732 return result; | |
733 } | |
734 | |
735 void CCThreadProxy::acquireLayerTextures() | |
736 { | |
737 // Called when the main thread needs to modify a layer texture that is used | |
738 // directly by the compositor. | |
739 // This method will block until the next compositor draw if there is a | |
740 // previously committed frame that is still undrawn. This is necessary to | |
741 // ensure that the main thread does not monopolize access to the textures. | |
742 ASSERT(isMainThread()); | |
743 | |
744 if (m_texturesAcquired) | |
745 return; | |
746 | |
747 TRACE_EVENT0("cc", "CCThreadProxy::acquireLayerTextures"); | |
748 DebugScopedSetMainThreadBlocked mainThreadBlocked; | |
749 CCCompletionEvent completion; | |
750 CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy::acq
uireLayerTexturesForMainThreadOnImplThread, &completion)); | |
751 completion.wait(); // Block until it is safe to write to layer textures from
the main thread. | |
752 | |
753 m_texturesAcquired = true; | |
754 } | |
755 | |
756 void CCThreadProxy::acquireLayerTexturesForMainThreadOnImplThread(CCCompletionEv
ent* completion) | |
757 { | |
758 ASSERT(isImplThread()); | |
759 ASSERT(!m_textureAcquisitionCompletionEventOnImplThread); | |
760 | |
761 m_textureAcquisitionCompletionEventOnImplThread = completion; | |
762 m_schedulerOnImplThread->setMainThreadNeedsLayerTextures(); | |
763 } | |
764 | |
765 void CCThreadProxy::scheduledActionAcquireLayerTexturesForMainThread() | |
766 { | |
767 ASSERT(m_textureAcquisitionCompletionEventOnImplThread); | |
768 m_textureAcquisitionCompletionEventOnImplThread->signal(); | |
769 m_textureAcquisitionCompletionEventOnImplThread = 0; | |
770 } | |
771 | |
772 CCScheduledActionDrawAndSwapResult CCThreadProxy::scheduledActionDrawAndSwapIfPo
ssible() | |
773 { | |
774 return scheduledActionDrawAndSwapInternal(false); | |
775 } | |
776 | |
777 CCScheduledActionDrawAndSwapResult CCThreadProxy::scheduledActionDrawAndSwapForc
ed() | |
778 { | |
779 return scheduledActionDrawAndSwapInternal(true); | |
780 } | |
781 | |
782 void CCThreadProxy::didAnticipatedDrawTimeChange(base::TimeTicks time) | |
783 { | |
784 if (!m_currentTextureUpdateControllerOnImplThread) | |
785 return; | |
786 | |
787 m_currentTextureUpdateControllerOnImplThread->performMoreUpdates(time); | |
788 } | |
789 | |
790 void CCThreadProxy::readyToFinalizeTextureUpdates() | |
791 { | |
792 ASSERT(isImplThread()); | |
793 m_schedulerOnImplThread->beginFrameComplete(); | |
794 } | |
795 | |
796 void CCThreadProxy::didCommitAndDrawFrame() | |
797 { | |
798 ASSERT(isMainThread()); | |
799 if (!m_layerTreeHost) | |
800 return; | |
801 m_layerTreeHost->didCommitAndDrawFrame(); | |
802 } | |
803 | |
804 void CCThreadProxy::didCompleteSwapBuffers() | |
805 { | |
806 ASSERT(isMainThread()); | |
807 if (!m_layerTreeHost) | |
808 return; | |
809 m_layerTreeHost->didCompleteSwapBuffers(); | |
810 } | |
811 | |
812 void CCThreadProxy::setAnimationEvents(CCAnimationEventsVector* passed_events, d
ouble wallClockTime) | |
813 { | |
814 scoped_ptr<CCAnimationEventsVector> events(make_scoped_ptr(passed_events)); | |
815 | |
816 TRACE_EVENT0("cc", "CCThreadProxy::setAnimationEvents"); | |
817 ASSERT(isMainThread()); | |
818 if (!m_layerTreeHost) | |
819 return; | |
820 m_layerTreeHost->setAnimationEvents(events.Pass(), wallClockTime); | |
821 } | |
822 | |
823 class CCThreadProxyContextRecreationTimer : public CCTimer, CCTimerClient { | |
824 public: | |
825 static PassOwnPtr<CCThreadProxyContextRecreationTimer> create(CCThreadProxy*
proxy) { return adoptPtr(new CCThreadProxyContextRecreationTimer(proxy)); } | |
826 | |
827 virtual void onTimerFired() OVERRIDE | |
828 { | |
829 m_proxy->tryToRecreateContext(); | |
830 } | |
831 | |
832 private: | |
833 explicit CCThreadProxyContextRecreationTimer(CCThreadProxy* proxy) | |
834 : CCTimer(CCProxy::mainThread(), this) | |
835 , m_proxy(proxy) | |
836 { | |
837 } | |
838 | |
839 CCThreadProxy* m_proxy; | |
840 }; | |
841 | |
842 void CCThreadProxy::beginContextRecreation() | |
843 { | |
844 TRACE_EVENT0("cc", "CCThreadProxy::beginContextRecreation"); | |
845 ASSERT(isMainThread()); | |
846 ASSERT(!m_contextRecreationTimer); | |
847 m_contextRecreationTimer = CCThreadProxyContextRecreationTimer::create(this)
; | |
848 m_layerTreeHost->didLoseContext(); | |
849 m_contextRecreationTimer->startOneShot(contextRecreationTickRate); | |
850 } | |
851 | |
852 void CCThreadProxy::tryToRecreateContext() | |
853 { | |
854 ASSERT(isMainThread()); | |
855 ASSERT(m_layerTreeHost); | |
856 CCLayerTreeHost::RecreateResult result = m_layerTreeHost->recreateContext(); | |
857 if (result == CCLayerTreeHost::RecreateFailedButTryAgain) | |
858 m_contextRecreationTimer->startOneShot(contextRecreationTickRate); | |
859 else if (result == CCLayerTreeHost::RecreateSucceeded) | |
860 m_contextRecreationTimer.clear(); | |
861 } | |
862 | |
863 void CCThreadProxy::initializeImplOnImplThread(CCCompletionEvent* completion, CC
InputHandler* handler) | |
864 { | |
865 TRACE_EVENT0("cc", "CCThreadProxy::initializeImplOnImplThread"); | |
866 ASSERT(isImplThread()); | |
867 m_layerTreeHostImpl = m_layerTreeHost->createLayerTreeHostImpl(this); | |
868 const base::TimeDelta displayRefreshInterval = base::TimeDelta::FromMicrosec
onds(base::Time::kMicrosecondsPerSecond / 60); | |
869 scoped_ptr<CCFrameRateController> frameRateController; | |
870 if (m_renderVSyncEnabled) | |
871 frameRateController.reset(new CCFrameRateController(CCDelayBasedTimeSour
ce::create(displayRefreshInterval, CCProxy::implThread()))); | |
872 else | |
873 frameRateController.reset(new CCFrameRateController(CCProxy::implThread(
))); | |
874 m_schedulerOnImplThread = CCScheduler::create(this, frameRateController.Pass
()); | |
875 m_schedulerOnImplThread->setVisible(m_layerTreeHostImpl->visible()); | |
876 | |
877 m_inputHandlerOnImplThread = scoped_ptr<CCInputHandler>(handler); | |
878 if (m_inputHandlerOnImplThread.get()) | |
879 m_inputHandlerOnImplThread->bindToClient(m_layerTreeHostImpl.get()); | |
880 | |
881 completion->signal(); | |
882 } | |
883 | |
884 void CCThreadProxy::initializeContextOnImplThread(CCGraphicsContext* context) | |
885 { | |
886 TRACE_EVENT0("cc", "CCThreadProxy::initializeContextOnImplThread"); | |
887 ASSERT(isImplThread()); | |
888 m_contextBeforeInitializationOnImplThread = scoped_ptr<CCGraphicsContext>(co
ntext).Pass(); | |
889 } | |
890 | |
891 void CCThreadProxy::initializeRendererOnImplThread(CCCompletionEvent* completion
, bool* initializeSucceeded, RendererCapabilities* capabilities) | |
892 { | |
893 TRACE_EVENT0("cc", "CCThreadProxy::initializeRendererOnImplThread"); | |
894 ASSERT(isImplThread()); | |
895 ASSERT(m_contextBeforeInitializationOnImplThread.get()); | |
896 *initializeSucceeded = m_layerTreeHostImpl->initializeRenderer(m_contextBefo
reInitializationOnImplThread.Pass()); | |
897 if (*initializeSucceeded) { | |
898 *capabilities = m_layerTreeHostImpl->rendererCapabilities(); | |
899 m_schedulerOnImplThread->setSwapBuffersCompleteSupported( | |
900 capabilities->usingSwapCompleteCallback); | |
901 } | |
902 | |
903 completion->signal(); | |
904 } | |
905 | |
906 void CCThreadProxy::layerTreeHostClosedOnImplThread(CCCompletionEvent* completio
n) | |
907 { | |
908 TRACE_EVENT0("cc", "CCThreadProxy::layerTreeHostClosedOnImplThread"); | |
909 ASSERT(isImplThread()); | |
910 m_layerTreeHost->deleteContentsTexturesOnImplThread(m_layerTreeHostImpl->res
ourceProvider()); | |
911 m_inputHandlerOnImplThread.reset(); | |
912 m_layerTreeHostImpl.reset(); | |
913 m_schedulerOnImplThread.clear(); | |
914 completion->signal(); | |
915 } | |
916 | |
917 void CCThreadProxy::setFullRootLayerDamageOnImplThread() | |
918 { | |
919 ASSERT(isImplThread()); | |
920 m_layerTreeHostImpl->setFullRootLayerDamage(); | |
921 } | |
922 | |
923 size_t CCThreadProxy::maxPartialTextureUpdates() const | |
924 { | |
925 return CCTextureUpdateController::maxPartialTextureUpdates(); | |
926 } | |
927 | |
928 void CCThreadProxy::recreateContextOnImplThread(CCCompletionEvent* completion, C
CGraphicsContext* contextPtr, bool* recreateSucceeded, RendererCapabilities* cap
abilities) | |
929 { | |
930 TRACE_EVENT0("cc", "CCThreadProxy::recreateContextOnImplThread"); | |
931 ASSERT(isImplThread()); | |
932 m_layerTreeHost->deleteContentsTexturesOnImplThread(m_layerTreeHostImpl->res
ourceProvider()); | |
933 *recreateSucceeded = m_layerTreeHostImpl->initializeRenderer(scoped_ptr<CCGr
aphicsContext>(contextPtr).Pass()); | |
934 if (*recreateSucceeded) { | |
935 *capabilities = m_layerTreeHostImpl->rendererCapabilities(); | |
936 m_schedulerOnImplThread->didRecreateContext(); | |
937 } | |
938 completion->signal(); | |
939 } | |
940 | |
941 void CCThreadProxy::renderingStatsOnImplThread(CCCompletionEvent* completion, CC
RenderingStats* stats) | |
942 { | |
943 ASSERT(isImplThread()); | |
944 m_layerTreeHostImpl->renderingStats(stats); | |
945 completion->signal(); | |
946 } | |
947 | |
948 CCThreadProxy::BeginFrameAndCommitState::BeginFrameAndCommitState() | |
949 : monotonicFrameBeginTime(0) | |
950 { | |
951 } | |
952 | |
953 CCThreadProxy::BeginFrameAndCommitState::~BeginFrameAndCommitState() | |
954 { | |
955 } | |
956 | |
957 } // namespace cc | |
OLD | NEW |