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