[Chromium] Incremental texture updates are not atomic.
[WebKit-https.git] / Source / WebCore / platform / graphics / chromium / cc / CCThreadProxy.cpp
1 /*
2  * Copyright (C) 2011 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1.  Redistributions of source code must retain the above copyright
8  *     notice, this list of conditions and the following disclaimer.
9  * 2.  Redistributions in binary form must reproduce the above copyright
10  *     notice, this list of conditions and the following disclaimer in the
11  *     documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
15  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
16  * DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
17  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
18  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
19  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
20  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
22  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24
25 #include "config.h"
26
27 #include "cc/CCThreadProxy.h"
28
29 #include "GraphicsContext3D.h"
30 #include "TraceEvent.h"
31 #include "cc/CCDelayBasedTimeSource.h"
32 #include "cc/CCFrameRateController.h"
33 #include "cc/CCInputHandler.h"
34 #include "cc/CCLayerTreeHost.h"
35 #include "cc/CCScheduler.h"
36 #include "cc/CCScopedThreadProxy.h"
37 #include "cc/CCTextureUpdater.h"
38 #include "cc/CCThreadTask.h"
39 #include <wtf/CurrentTime.h>
40 #include <wtf/MainThread.h>
41
42 using namespace WTF;
43
44 namespace {
45
46 static const size_t textureUpdatesPerFrame = 0;
47
48 } // anonymous namespace
49
50 namespace WebCore {
51
52 PassOwnPtr<CCProxy> CCThreadProxy::create(CCLayerTreeHost* layerTreeHost)
53 {
54     return adoptPtr(new CCThreadProxy(layerTreeHost));
55 }
56
57 CCThreadProxy::CCThreadProxy(CCLayerTreeHost* layerTreeHost)
58     : m_animateRequested(false)
59     , m_commitRequested(false)
60     , m_layerTreeHost(layerTreeHost)
61     , m_compositorIdentifier(-1)
62     , m_started(false)
63     , m_lastExecutedBeginFrameAndCommitSequenceNumber(-1)
64     , m_numBeginFrameAndCommitsIssuedOnImplThread(0)
65     , m_mainThreadProxy(CCScopedThreadProxy::create(CCProxy::mainThread()))
66     , m_readbackRequestOnImplThread(0)
67     , m_finishAllRenderingCompletionEventOnImplThread(0)
68     , m_commitCompletionEventOnImplThread(0)
69     , m_nextFrameIsNewlyCommittedFrameOnImplThread(false)
70 {
71     TRACE_EVENT("CCThreadProxy::CCThreadProxy", this, 0);
72     ASSERT(isMainThread());
73 }
74
75 CCThreadProxy::~CCThreadProxy()
76 {
77     TRACE_EVENT("CCThreadProxy::~CCThreadProxy", this, 0);
78     ASSERT(isMainThread());
79     ASSERT(!m_started);
80 }
81
82 bool CCThreadProxy::compositeAndReadback(void *pixels, const IntRect& rect)
83 {
84     TRACE_EVENT("CCThreadPRoxy::compositeAndReadback", this, 0);
85     ASSERT(isMainThread());
86     ASSERT(m_layerTreeHost);
87
88     // If a commit is pending, perform the commit first.
89     if (m_commitRequested)  {
90         // This bit of code is uglier than it should be because returning
91         // pointers via the CCThread task model is really messy. Effectively, we
92         // are making a blocking call to createBeginFrameAndCommitTaskOnImplThread,
93         // and trying to get the CCMainThread::Task it returns so we can run it.
94         OwnPtr<CCThread::Task> beginFrameAndCommitTask;
95         {
96             CCThread::Task* taskPtr = 0;
97             CCCompletionEvent completion;
98             CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy::obtainBeginFrameAndCommitTaskFromCCThread, AllowCrossThreadAccess(&completion), AllowCrossThreadAccess(&taskPtr)));
99             completion.wait();
100             beginFrameAndCommitTask = adoptPtr(taskPtr);
101         }
102
103         beginFrameAndCommitTask->performTask();
104     }
105
106     // Draw using the new tree and read back the results.
107     ReadbackRequest request;
108     request.rect = rect;
109     request.pixels = pixels;
110     CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy::requestReadbackOnImplThread, AllowCrossThreadAccess(&request)));
111     request.completion.wait();
112     return request.success;
113 }
114
115 void CCThreadProxy::requestReadbackOnImplThread(ReadbackRequest* request)
116 {
117     ASSERT(CCProxy::isImplThread());
118     ASSERT(!m_readbackRequestOnImplThread);
119     if (!m_layerTreeHostImpl) {
120         request->success = false;
121         request->completion.signal();
122         return;
123     }
124     m_readbackRequestOnImplThread = request;
125     m_schedulerOnImplThread->setNeedsForcedRedraw();
126 }
127
128 GraphicsContext3D* CCThreadProxy::context()
129 {
130     return 0;
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     CCCompletionEvent completion;
139     CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy::finishAllRenderingOnImplThread, AllowCrossThreadAccess(&completion)));
140     completion.wait();
141 }
142
143 bool CCThreadProxy::isStarted() const
144 {
145     ASSERT(CCProxy::isMainThread());
146     return m_started;
147 }
148
149 bool CCThreadProxy::initializeLayerRenderer()
150 {
151     TRACE_EVENT("CCThreadProxy::initializeLayerRenderer", this, 0);
152     RefPtr<GraphicsContext3D> context = m_layerTreeHost->createLayerTreeHostContext3D();
153     if (!context)
154         return false;
155     ASSERT(context->hasOneRef());
156
157     // Leak the context pointer so we can transfer ownership of it to the other side...
158     GraphicsContext3D* contextPtr = context.release().leakRef();
159     ASSERT(contextPtr->hasOneRef());
160
161     // Make a blocking call to initializeLayerRendererOnImplThread. The results of that call
162     // are pushed into the initializeSucceeded and capabilities local variables.
163     CCCompletionEvent completion;
164     bool initializeSucceeded = false;
165     LayerRendererCapabilities capabilities;
166     CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy::initializeLayerRendererOnImplThread,
167                                           AllowCrossThreadAccess(contextPtr), AllowCrossThreadAccess(&completion),
168                                           AllowCrossThreadAccess(&initializeSucceeded), AllowCrossThreadAccess(&capabilities),
169                                           AllowCrossThreadAccess(&m_compositorIdentifier)));
170     completion.wait();
171
172     if (initializeSucceeded)
173         m_layerRendererCapabilitiesMainThreadCopy = capabilities;
174     return initializeSucceeded;
175 }
176
177 int CCThreadProxy::compositorIdentifier() const
178 {
179     ASSERT(isMainThread());
180     return m_compositorIdentifier;
181 }
182
183 const LayerRendererCapabilities& CCThreadProxy::layerRendererCapabilities() const
184 {
185     return m_layerRendererCapabilitiesMainThreadCopy;
186 }
187
188 void CCThreadProxy::loseCompositorContext(int numTimes)
189 {
190     ASSERT_NOT_REACHED();
191 }
192
193 void CCThreadProxy::setNeedsAnimate()
194 {
195     ASSERT(isMainThread());
196     if (m_animateRequested)
197         return;
198
199     TRACE_EVENT("CCThreadProxy::setNeedsAnimate", this, 0);
200     m_animateRequested = true;
201     setNeedsCommit();
202 }
203
204 void CCThreadProxy::setNeedsCommit()
205 {
206     ASSERT(isMainThread());
207     if (m_commitRequested)
208         return;
209
210     TRACE_EVENT("CCThreadProxy::setNeedsCommit", this, 0);
211     m_commitRequested = true;
212     CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy::setNeedsCommitOnImplThread));
213 }
214
215 void CCThreadProxy::onSwapBuffersCompleteOnImplThread()
216 {
217     ASSERT(isImplThread());
218     TRACE_EVENT("CCThreadProxy::onSwapBuffersCompleteOnImplThread", this, 0);
219     m_schedulerOnImplThread->didSwapBuffersComplete();
220     m_mainThreadProxy->postTask(createCCThreadTask(this, &CCThreadProxy::didCompleteSwapBuffers));
221 }
222
223 void CCThreadProxy::setNeedsCommitOnImplThread()
224 {
225     ASSERT(isImplThread());
226     TRACE_EVENT("CCThreadProxy::setNeedsCommitOnImplThread", this, 0);
227     m_schedulerOnImplThread->setNeedsCommit();
228 }
229
230 void CCThreadProxy::setNeedsRedraw()
231 {
232     ASSERT(isMainThread());
233     TRACE_EVENT("CCThreadProxy::setNeedsRedraw", this, 0);
234     CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy::setNeedsRedrawOnImplThread));
235 }
236
237 void CCThreadProxy::setVisible(bool visible)
238 {
239     ASSERT(isMainThread());
240     CCCompletionEvent completion;
241     CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy::setVisibleOnImplThread, AllowCrossThreadAccess(&completion), visible));
242     completion.wait();
243 }
244
245 void CCThreadProxy::setVisibleOnImplThread(CCCompletionEvent* completion, bool visible)
246 {
247     ASSERT(isImplThread());
248     m_schedulerOnImplThread->setVisible(visible);
249     m_layerTreeHostImpl->setVisible(visible);
250     if (!visible) {
251         m_layerTreeHost->didBecomeInvisibleOnImplThread(m_layerTreeHostImpl.get());
252         // as partial or all the textures may be evicted in didBecomeInvisibleOnImplThread,
253         // schedule a commit which will be executed when it goes to visible again.
254         m_schedulerOnImplThread->setNeedsCommit();
255     } else
256         m_schedulerOnImplThread->setNeedsRedraw();
257     completion->signal();
258 }
259
260 void CCThreadProxy::setNeedsRedrawOnImplThread()
261 {
262     ASSERT(isImplThread());
263     TRACE_EVENT("CCThreadProxy::setNeedsRedrawOnImplThread", this, 0);
264     m_schedulerOnImplThread->setNeedsRedraw();
265 }
266
267 void CCThreadProxy::start()
268 {
269     ASSERT(isMainThread());
270     ASSERT(CCProxy::implThread());
271     // Create LayerTreeHostImpl.
272     CCCompletionEvent completion;
273     CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy::initializeImplOnImplThread, AllowCrossThreadAccess(&completion)));
274     completion.wait();
275
276     m_started = true;
277 }
278
279 void CCThreadProxy::stop()
280 {
281     TRACE_EVENT("CCThreadProxy::stop", this, 0);
282     ASSERT(isMainThread());
283     ASSERT(m_started);
284
285     // Synchronously deletes the impl.
286     CCCompletionEvent completion;
287     CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy::layerTreeHostClosedOnImplThread, AllowCrossThreadAccess(&completion)));
288     completion.wait();
289
290     m_mainThreadProxy->shutdown(); // Stop running tasks posted to us.
291
292     ASSERT(!m_layerTreeHostImpl); // verify that the impl deleted.
293     m_layerTreeHost = 0;
294     m_started = false;
295 }
296
297 void CCThreadProxy::finishAllRenderingOnImplThread(CCCompletionEvent* completion)
298 {
299     TRACE_EVENT("CCThreadProxy::finishAllRenderingOnImplThread", this, 0);
300     ASSERT(isImplThread());
301     ASSERT(!m_finishAllRenderingCompletionEventOnImplThread);
302     m_finishAllRenderingCompletionEventOnImplThread = completion;
303
304     m_schedulerOnImplThread->setNeedsForcedRedraw();
305 }
306
307 void CCThreadProxy::scheduledActionBeginFrame()
308 {
309     TRACE_EVENT("CCThreadProxy::scheduledActionBeginFrame", this, 0);
310     m_mainThreadProxy->postTask(createBeginFrameAndCommitTaskOnImplThread());
311 }
312
313 void CCThreadProxy::obtainBeginFrameAndCommitTaskFromCCThread(CCCompletionEvent* completion, CCThread::Task** taskPtr)
314 {
315     OwnPtr<CCThread::Task> task = createBeginFrameAndCommitTaskOnImplThread();
316     *taskPtr = task.leakPtr();
317     completion->signal();
318 }
319
320 PassOwnPtr<CCThread::Task> CCThreadProxy::createBeginFrameAndCommitTaskOnImplThread()
321 {
322     TRACE_EVENT("CCThreadProxy::createBeginFrameAndCommitTaskOnImplThread", this, 0);
323     ASSERT(isImplThread());
324     double frameBeginTime = currentTime();
325
326     // NOTE, it is possible to receieve a request for a
327     // beginFrameAndCommitOnImplThread from finishAllRendering while a
328     // beginFrameAndCommitOnImplThread is enqueued. Since CCThread doesn't
329     // provide a threadsafe way to cancel tasks, it is important that
330     // beginFrameAndCommit be structured to understand that it may get called at
331     // a point that it shouldn't. We do this by assigning a sequence number to
332     // every new beginFrameAndCommit task. Then, beginFrameAndCommit tracks the
333     // last executed sequence number, dropping beginFrameAndCommit with sequence
334     // numbers below the last executed one.
335     int thisTaskSequenceNumber = m_numBeginFrameAndCommitsIssuedOnImplThread;
336     m_numBeginFrameAndCommitsIssuedOnImplThread++;
337     OwnPtr<CCScrollAndScaleSet> scrollInfo = m_layerTreeHostImpl->processScrollDeltas();
338     return createCCThreadTask(this, &CCThreadProxy::beginFrameAndCommit, thisTaskSequenceNumber, frameBeginTime, scrollInfo.release());
339 }
340
341 void CCThreadProxy::beginFrameAndCommit(int sequenceNumber, double frameBeginTime, PassOwnPtr<CCScrollAndScaleSet> scrollInfo)
342 {
343     TRACE_EVENT("CCThreadProxy::beginFrameAndCommit", this, 0);
344     ASSERT(isMainThread());
345     if (!m_layerTreeHost)
346         return;
347
348     // Drop beginFrameAndCommit calls that occur out of sequence. See createBeginFrameAndCommitTaskOnImplThread for
349     // an explanation of how out-of-sequence beginFrameAndCommit tasks can occur.
350     if (sequenceNumber < m_lastExecutedBeginFrameAndCommitSequenceNumber) {
351         TRACE_EVENT("EarlyOut_StaleBeginFrameAndCommit", this, 0);
352         return;
353     }
354     m_lastExecutedBeginFrameAndCommitSequenceNumber = sequenceNumber;
355
356     // Do not notify the impl thread of commit requests that occur during
357     // the apply/animate/layout part of the beginFrameAndCommit process since
358     // those commit requests will get painted immediately. Once we have done
359     // the paint, m_commitRequested will be set to false to allow new commit
360     // requests to be scheduled.
361     m_commitRequested = true;
362
363     // On the other hand, the animationRequested flag needs to be cleared
364     // here so that any animation requests generated by the apply or animate
365     // callbacks will trigger another frame.
366     m_animateRequested = false;
367
368     // FIXME: technically, scroll deltas need to be applied for dropped commits as well.
369     // Re-do the commit flow so that we don't send the scrollInfo on the BFAC message.
370     m_layerTreeHost->applyScrollAndScale(*scrollInfo);
371
372     // FIXME: recreate the context if it was requested by the impl thread.
373     m_layerTreeHost->updateAnimations(frameBeginTime);
374     m_layerTreeHost->layout();
375
376     ASSERT(m_lastExecutedBeginFrameAndCommitSequenceNumber == sequenceNumber);
377
378     // Clear the commit flag after updating animations and layout here --- objects that only
379     // layout when painted will trigger another setNeedsCommit inside
380     // updateLayers.
381     m_commitRequested = false;
382
383     m_layerTreeHost->updateLayers();
384
385     // Before applying scrolls and calling animate, we set m_animateRequested to false.
386     // If it is true now, it means setNeedAnimate was called again. Call setNeedsCommit
387     // now so that we get begin frame when this one is done.
388     if (m_animateRequested)
389         setNeedsCommit();
390
391     // Notify the impl thread that the beginFrame has completed. This will
392     // begin the commit process, which is blocking from the main thread's
393     // point of view, but asynchronously performed on the impl thread,
394     // coordinated by the CCScheduler.
395     {
396         TRACE_EVENT("commit", this, 0);
397         CCCompletionEvent completion;
398         CCProxy::implThread()->postTask(createCCThreadTask(this, &CCThreadProxy::beginFrameCompleteOnImplThread, AllowCrossThreadAccess(&completion)));
399         completion.wait();
400     }
401
402     m_layerTreeHost->commitComplete();
403
404     ASSERT(m_lastExecutedBeginFrameAndCommitSequenceNumber == sequenceNumber);
405 }
406
407 void CCThreadProxy::beginFrameCompleteOnImplThread(CCCompletionEvent* completion)
408 {
409     TRACE_EVENT("CCThreadProxy::beginFrameCompleteOnImplThread", this, 0);
410     ASSERT(!m_commitCompletionEventOnImplThread);
411     ASSERT(isImplThread());
412     ASSERT(m_schedulerOnImplThread);
413     ASSERT(m_schedulerOnImplThread->commitPending());
414     if (!m_layerTreeHostImpl) {
415         completion->signal();
416         return;
417     }
418
419     m_commitCompletionEventOnImplThread = completion;
420
421     ASSERT(!m_currentTextureUpdaterOnImplThread);
422     m_currentTextureUpdaterOnImplThread = adoptPtr(new CCTextureUpdater(m_layerTreeHostImpl->contentsTextureAllocator()));
423     m_layerTreeHost->updateCompositorResources(m_layerTreeHostImpl->context(), *m_currentTextureUpdaterOnImplThread);
424
425     m_schedulerOnImplThread->beginFrameComplete();
426 }
427
428 bool CCThreadProxy::hasMoreResourceUpdates() const
429 {
430     if (!m_currentTextureUpdaterOnImplThread)
431         return false;
432     return m_currentTextureUpdaterOnImplThread->hasMoreUpdates();
433 }
434
435 bool CCThreadProxy::canDraw()
436 {
437     ASSERT(isImplThread());
438     if (!m_layerTreeHostImpl)
439         return false;
440     return m_layerTreeHostImpl->canDraw();
441 }
442
443 void CCThreadProxy::scheduledActionUpdateMoreResources()
444 {
445     TRACE_EVENT("CCThreadProxy::scheduledActionUpdateMoreResources", this, 0);
446     ASSERT(m_currentTextureUpdaterOnImplThread);
447     m_currentTextureUpdaterOnImplThread->update(m_layerTreeHostImpl->context(), textureUpdatesPerFrame > 0 ? textureUpdatesPerFrame : 99999);
448 }
449
450 void CCThreadProxy::scheduledActionCommit()
451 {
452     TRACE_EVENT("CCThreadProxy::scheduledActionCommit", this, 0);
453     ASSERT(m_currentTextureUpdaterOnImplThread);
454     ASSERT(!m_currentTextureUpdaterOnImplThread->hasMoreUpdates());
455     ASSERT(m_commitCompletionEventOnImplThread);
456
457     m_currentTextureUpdaterOnImplThread.clear();
458
459
460     m_layerTreeHostImpl->beginCommit();
461
462     m_layerTreeHost->beginCommitOnImplThread(m_layerTreeHostImpl.get());
463     m_layerTreeHost->finishCommitOnImplThread(m_layerTreeHostImpl.get());
464
465     m_layerTreeHostImpl->commitComplete();
466
467     m_nextFrameIsNewlyCommittedFrameOnImplThread = true;
468
469     m_commitCompletionEventOnImplThread->signal();
470     m_commitCompletionEventOnImplThread = 0;
471 }
472
473 void CCThreadProxy::scheduledActionDrawAndSwap()
474 {
475     TRACE_EVENT("CCThreadProxy::scheduledActionDrawAndSwap", this, 0);
476     ASSERT(isImplThread());
477     if (!m_layerTreeHostImpl)
478         return;
479
480     // FIXME: compute the frame display time more intelligently
481     double frameDisplayTimeMs = monotonicallyIncreasingTime() * 1000.0;
482
483     m_inputHandlerOnImplThread->willDraw(frameDisplayTimeMs);
484     m_layerTreeHostImpl->animate(frameDisplayTimeMs);
485     m_layerTreeHostImpl->drawLayers();
486
487     // Check for a pending compositeAndReadback.
488     if (m_readbackRequestOnImplThread) {
489       m_layerTreeHostImpl->readback(m_readbackRequestOnImplThread->pixels, m_readbackRequestOnImplThread->rect);
490       m_readbackRequestOnImplThread->success = !m_layerTreeHostImpl->isContextLost();
491       m_readbackRequestOnImplThread->completion.signal();
492       m_readbackRequestOnImplThread = 0;
493     }
494
495     m_layerTreeHostImpl->swapBuffers();
496
497     // FIXME: handle case where m_layerTreeHostImpl->isContextLost.
498     // FIXME: pass didSwapBuffersAbort if m_layerTreeHostImpl->isContextLost.
499     ASSERT(!m_layerTreeHostImpl->isContextLost());
500
501     // Process any finish request
502     if (m_finishAllRenderingCompletionEventOnImplThread) {
503         m_layerTreeHostImpl->finishAllRendering();
504         m_finishAllRenderingCompletionEventOnImplThread->signal();
505         m_finishAllRenderingCompletionEventOnImplThread = 0;
506     }
507
508     // Tell the main thread that the the newly-commited frame was drawn.
509     if (m_nextFrameIsNewlyCommittedFrameOnImplThread) {
510         m_nextFrameIsNewlyCommittedFrameOnImplThread = false;
511         m_mainThreadProxy->postTask(createCCThreadTask(this, &CCThreadProxy::didCommitAndDrawFrame));
512     }
513 }
514
515 void CCThreadProxy::didCommitAndDrawFrame()
516 {
517     ASSERT(isMainThread());
518     if (!m_layerTreeHost)
519         return;
520     m_layerTreeHost->didCommitAndDrawFrame();
521 }
522
523 void CCThreadProxy::didCompleteSwapBuffers()
524 {
525     ASSERT(isMainThread());
526     if (!m_layerTreeHost)
527         return;
528     m_layerTreeHost->didCompleteSwapBuffers();
529 }
530
531 void CCThreadProxy::initializeImplOnImplThread(CCCompletionEvent* completion)
532 {
533     TRACE_EVENT("CCThreadProxy::initializeImplOnImplThread", this, 0);
534     ASSERT(isImplThread());
535     m_layerTreeHostImpl = m_layerTreeHost->createLayerTreeHostImpl(this);
536     ASSERT(m_layerTreeHostImpl->settings().refreshRate > 0);
537     const double displayRefreshIntervalMs = 1000.0 / m_layerTreeHostImpl->settings().refreshRate;
538     OwnPtr<CCFrameRateController> frameRateController = adoptPtr(new CCFrameRateController(CCDelayBasedTimeSource::create(displayRefreshIntervalMs, CCProxy::implThread())));
539     m_schedulerOnImplThread = CCScheduler::create(this, frameRateController.release());
540     m_schedulerOnImplThread->setVisible(m_layerTreeHostImpl->visible());
541     completion->signal();
542 }
543
544 void CCThreadProxy::initializeLayerRendererOnImplThread(GraphicsContext3D* contextPtr, CCCompletionEvent* completion, bool* initializeSucceeded, LayerRendererCapabilities* capabilities, int* compositorIdentifier)
545 {
546     TRACE_EVENT("CCThreadProxy::initializeLayerRendererOnImplThread", this, 0);
547     ASSERT(isImplThread());
548     RefPtr<GraphicsContext3D> context(adoptRef(contextPtr));
549     *initializeSucceeded = m_layerTreeHostImpl->initializeLayerRenderer(context);
550     if (*initializeSucceeded) {
551         *capabilities = m_layerTreeHostImpl->layerRendererCapabilities();
552         if (capabilities->usingSwapCompleteCallback)
553             m_schedulerOnImplThread->setMaxFramesPending(2);
554
555         m_inputHandlerOnImplThread = CCInputHandler::create(m_layerTreeHostImpl.get());
556         *compositorIdentifier = m_inputHandlerOnImplThread->identifier();
557     }
558
559     completion->signal();
560 }
561
562 void CCThreadProxy::layerTreeHostClosedOnImplThread(CCCompletionEvent* completion)
563 {
564     TRACE_EVENT("CCThreadProxy::layerTreeHostClosedOnImplThread", this, 0);
565     ASSERT(isImplThread());
566     m_layerTreeHost->deleteContentsTexturesOnImplThread(m_layerTreeHostImpl->contentsTextureAllocator());
567     m_layerTreeHostImpl.clear();
568     m_inputHandlerOnImplThread.clear();
569     m_schedulerOnImplThread.clear();
570     completion->signal();
571 }
572
573 bool CCThreadProxy::partialTextureUpdateCapability() const
574 {
575     return !textureUpdatesPerFrame;
576 }
577
578 } // namespace WebCore