9ee164a5cef2b5cabcee3ecc5f7d1d4179c9733f
[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/CCInputHandler.h"
32 #include "cc/CCLayerTreeHost.h"
33 #include "cc/CCMainThreadTask.h"
34 #include "cc/CCScheduler.h"
35 #include "cc/CCScrollController.h"
36 #include "cc/CCThreadTask.h"
37 #include <wtf/CurrentTime.h>
38 #include <wtf/MainThread.h>
39
40 using namespace WTF;
41
42 namespace WebCore {
43
44 CCThread* CCThreadProxy::s_ccThread = 0;
45
46 void CCThreadProxy::setThread(CCThread* ccThread)
47 {
48     s_ccThread = ccThread;
49 #ifndef NDEBUG
50     CCProxy::setImplThread(s_ccThread->threadID());
51 #endif
52 }
53
54 class CCThreadProxySchedulerClient : public CCSchedulerClient {
55 public:
56     static PassOwnPtr<CCThreadProxySchedulerClient> create(CCThreadProxy* proxy)
57     {
58         return adoptPtr(new CCThreadProxySchedulerClient(proxy));
59     }
60     virtual ~CCThreadProxySchedulerClient() { }
61
62     virtual void scheduleBeginFrameAndCommit()
63     {
64         CCMainThread::postTask(m_proxy->createBeginFrameAndCommitTaskOnCCThread());
65     }
66
67     virtual void scheduleDrawAndPresent()
68     {
69         m_proxy->drawLayersAndPresentOnCCThread();
70     }
71
72 private:
73     explicit CCThreadProxySchedulerClient(CCThreadProxy* proxy)
74     {
75         m_proxy = proxy;
76     }
77
78     CCThreadProxy* m_proxy;
79 };
80
81 class CCThreadProxyScrollControllerAdapter : public CCScrollController {
82 public:
83     static PassOwnPtr<CCThreadProxyScrollControllerAdapter> create(CCThreadProxy* proxy)
84     {
85         return adoptPtr(new CCThreadProxyScrollControllerAdapter(proxy));
86     }
87     virtual ~CCThreadProxyScrollControllerAdapter() { }
88
89     virtual void scrollRootLayer(const IntSize& offset)
90     {
91         m_proxy->m_layerTreeHostImpl->scrollRootLayer(offset);
92         m_proxy->setNeedsRedrawOnCCThread();
93         m_proxy->setNeedsCommitOnCCThread();
94     }
95
96 private:
97     explicit CCThreadProxyScrollControllerAdapter(CCThreadProxy* proxy)
98     {
99         m_proxy = proxy;
100     }
101
102     CCThreadProxy* m_proxy;
103 };
104
105 PassOwnPtr<CCProxy> CCThreadProxy::create(CCLayerTreeHost* layerTreeHost)
106 {
107     return adoptPtr(new CCThreadProxy(layerTreeHost));
108 }
109
110 CCThreadProxy::CCThreadProxy(CCLayerTreeHost* layerTreeHost)
111     : m_commitRequested(false)
112     , m_layerTreeHost(layerTreeHost)
113     , m_compositorIdentifier(-1)
114     , m_started(false)
115     , m_lastExecutedBeginFrameAndCommitSequenceNumber(-1)
116     , m_numBeginFrameAndCommitsIssuedOnCCThread(0)
117 {
118     TRACE_EVENT("CCThreadProxy::CCThreadProxy", this, 0);
119     ASSERT(isMainThread());
120 }
121
122 CCThreadProxy::~CCThreadProxy()
123 {
124     TRACE_EVENT("CCThreadProxy::~CCThreadProxy", this, 0);
125     ASSERT(isMainThread());
126     ASSERT(!m_started);
127 }
128
129 bool CCThreadProxy::compositeAndReadback(void *pixels, const IntRect& rect)
130 {
131     TRACE_EVENT("CCThreadPRoxy::compositeAndReadback", this, 0);
132     ASSERT(isMainThread());
133     ASSERT(m_layerTreeHost);
134
135     // If a commit is pending, perform the commit first.
136     if (m_commitRequested)  {
137         // This bit of code is uglier than it should be because returning
138         // pointers via the CCThread task model is really messy. Effectively, we
139         // are making a blocking call to createBeginFrameAndCommitTaskOnCCThread,
140         // and trying to get the CCMainThread::Task it returns so we can run it.
141         OwnPtr<CCMainThread::Task> beginFrameAndCommitTask;
142         {
143             CCMainThread::Task* taskPtr = 0;
144             CCCompletionEvent completion;
145             s_ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::obtainBeginFrameAndCommitTaskFromCCThread, AllowCrossThreadAccess(&completion), AllowCrossThreadAccess(&taskPtr)));
146             completion.wait();
147             beginFrameAndCommitTask = adoptPtr(taskPtr);
148         }
149
150         beginFrameAndCommitTask->performTask();
151     }
152
153     // Draw using the new tree and read back the results.
154     bool success = false;
155     CCCompletionEvent completion;
156     s_ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::drawLayersAndReadbackOnCCThread, AllowCrossThreadAccess(&completion), AllowCrossThreadAccess(&success), AllowCrossThreadAccess(pixels), rect));
157     completion.wait();
158     return success;
159 }
160
161 void CCThreadProxy::drawLayersAndReadbackOnCCThread(CCCompletionEvent* completion, bool* success, void* pixels, const IntRect& rect)
162 {
163     ASSERT(CCProxy::isImplThread());
164     if (!m_layerTreeHostImpl) {
165         *success = false;
166         completion->signal();
167         return;
168     }
169     drawLayersOnCCThread();
170     m_layerTreeHostImpl->readback(pixels, rect);
171     *success = m_layerTreeHostImpl->isContextLost();
172     completion->signal();
173 }
174
175 GraphicsContext3D* CCThreadProxy::context()
176 {
177     return 0;
178 }
179
180 void CCThreadProxy::finishAllRendering()
181 {
182     ASSERT(CCProxy::isMainThread());
183
184     // Make sure all GL drawing is finished on the impl thread.
185     CCCompletionEvent completion;
186     s_ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::finishAllRenderingOnCCThread, AllowCrossThreadAccess(&completion)));
187     completion.wait();
188 }
189
190 bool CCThreadProxy::isStarted() const
191 {
192     ASSERT(CCProxy::isMainThread());
193     return m_started;
194 }
195
196 bool CCThreadProxy::initializeLayerRenderer()
197 {
198     TRACE_EVENT("CCThreadProxy::initializeLayerRenderer", this, 0);
199     RefPtr<GraphicsContext3D> context = m_layerTreeHost->createLayerTreeHostContext3D();
200     if (!context)
201         return false;
202     ASSERT(context->hasOneRef());
203
204     // Leak the context pointer so we can transfer ownership of it to the other side...
205     GraphicsContext3D* contextPtr = context.release().leakRef();
206     ASSERT(contextPtr->hasOneRef());
207
208     // Make a blocking call to initializeLayerRendererOnCCThread. The results of that call
209     // are pushed into the initializeSucceeded and capabilities local variables.
210     CCCompletionEvent completion;
211     bool initializeSucceeded = false;
212     LayerRendererCapabilities capabilities;
213     s_ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::initializeLayerRendererOnCCThread,
214                                           AllowCrossThreadAccess(contextPtr), AllowCrossThreadAccess(&completion),
215                                           AllowCrossThreadAccess(&initializeSucceeded), AllowCrossThreadAccess(&capabilities),
216                                           AllowCrossThreadAccess(&m_compositorIdentifier)));
217     completion.wait();
218
219     if (initializeSucceeded)
220         m_layerRendererCapabilitiesMainThreadCopy = capabilities;
221     return initializeSucceeded;
222 }
223
224 int CCThreadProxy::compositorIdentifier() const
225 {
226     ASSERT(isMainThread());
227     return m_compositorIdentifier;
228 }
229
230 const LayerRendererCapabilities& CCThreadProxy::layerRendererCapabilities() const
231 {
232     return m_layerRendererCapabilitiesMainThreadCopy;
233 }
234
235 void CCThreadProxy::loseCompositorContext(int numTimes)
236 {
237     ASSERT_NOT_REACHED();
238 }
239
240 void CCThreadProxy::setNeedsCommit()
241 {
242     ASSERT(isMainThread());
243     if (m_commitRequested)
244         return;
245
246     TRACE_EVENT("CCThreadProxy::setNeedsCommit", this, 0);
247     m_commitRequested = true;
248     s_ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::setNeedsCommitOnCCThread));
249 }
250
251 void CCThreadProxy::setNeedsCommitThenRedraw()
252 {
253     ASSERT(isMainThread());
254     m_redrawAfterCommit = true;
255     setNeedsCommit();
256 }
257
258 void CCThreadProxy::setNeedsCommitOnCCThread()
259 {
260     ASSERT(isImplThread());
261     TRACE_EVENT("CCThreadProxy::setNeedsCommitOnCCThread", this, 0);
262     m_schedulerOnCCThread->requestCommit();
263 }
264
265 void CCThreadProxy::setNeedsRedraw()
266 {
267     ASSERT(isMainThread());
268     TRACE_EVENT("CCThreadProxy::setNeedsRedraw", this, 0);
269     s_ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::setNeedsRedrawOnCCThread));
270 }
271
272 void CCThreadProxy::setNeedsRedrawOnCCThread()
273 {
274     ASSERT(isImplThread());
275     TRACE_EVENT("CCThreadProxy::setNeedsRedrawOnCCThread", this, 0);
276     m_schedulerOnCCThread->requestRedraw();
277 }
278
279 void CCThreadProxy::start()
280 {
281     ASSERT(isMainThread());
282     ASSERT(s_ccThread);
283     // Create LayerTreeHostImpl.
284     CCCompletionEvent completion;
285     s_ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::initializeImplOnCCThread, AllowCrossThreadAccess(&completion)));
286     completion.wait();
287
288     m_started = true;
289 }
290
291 void CCThreadProxy::stop()
292 {
293     TRACE_EVENT("CCThreadProxy::stop", this, 0);
294     ASSERT(isMainThread());
295     ASSERT(m_started);
296
297     // Synchronously deletes the impl.
298     CCCompletionEvent completion;
299     s_ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::layerTreeHostClosedOnCCThread, AllowCrossThreadAccess(&completion)));
300     completion.wait();
301
302     ASSERT(!m_layerTreeHostImpl); // verify that the impl deleted.
303     m_layerTreeHost = 0;
304     m_started = false;
305 }
306
307 void CCThreadProxy::finishAllRenderingOnCCThread(CCCompletionEvent* completion)
308 {
309     TRACE_EVENT("CCThreadProxy::finishAllRenderingOnCCThread", this, 0);
310     ASSERT(isImplThread());
311     if (m_schedulerOnCCThread->redrawPending()) {
312         drawLayersOnCCThread();
313         m_layerTreeHostImpl->present();
314         m_schedulerOnCCThread->didDraw();
315     }
316     m_layerTreeHostImpl->finishAllRendering();
317     completion->signal();
318 }
319
320 void CCThreadProxy::obtainBeginFrameAndCommitTaskFromCCThread(CCCompletionEvent* completion, CCMainThread::Task** taskPtr)
321 {
322     OwnPtr<CCMainThread::Task> task = createBeginFrameAndCommitTaskOnCCThread();
323     *taskPtr = task.leakPtr();
324     completion->signal();
325 }
326
327 PassOwnPtr<CCMainThread::Task> CCThreadProxy::createBeginFrameAndCommitTaskOnCCThread()
328 {
329     TRACE_EVENT("CCThreadProxy::createBeginFrameAndCommitTaskOnCCThread", this, 0);
330     ASSERT(isImplThread());
331     double frameBeginTime = currentTime();
332
333     // NOTE, it is possible to receieve a request for a
334     // beginFrameAndCommitOnCCThread from finishAllRendering while a
335     // beginFrameAndCommitOnCCThread is enqueued. Since CCMainThread doesn't
336     // provide a threadsafe way to cancel tasks, it is important that
337     // beginFrameAndCommit be structured to understand that it may get called at
338     // a point that it shouldn't. We do this by assigning a sequence number to
339     // every new beginFrameAndCommit task. Then, beginFrameAndCommit tracks the
340     // last executed sequence number, dropping beginFrameAndCommit with sequence
341     // numbers below the last executed one.
342     int thisTaskSequenceNumber = m_numBeginFrameAndCommitsIssuedOnCCThread;
343     m_numBeginFrameAndCommitsIssuedOnCCThread++;
344     OwnPtr<CCScrollUpdateSet> scrollInfo = m_layerTreeHostImpl->processScrollDeltas();
345     return createMainThreadTask(this, &CCThreadProxy::beginFrameAndCommit, thisTaskSequenceNumber, frameBeginTime, scrollInfo.release());
346 }
347
348 void CCThreadProxy::beginFrameAndCommit(int sequenceNumber, double frameBeginTime, PassOwnPtr<CCScrollUpdateSet> scrollInfo)
349 {
350     TRACE_EVENT("CCThreadProxy::beginFrameAndCommit", this, 0);
351     ASSERT(isMainThread());
352     if (!m_layerTreeHost)
353         return;
354
355     // Scroll deltas need to be applied even if the commit will be dropped.
356     m_layerTreeHost->applyScrollDeltas(*scrollInfo.get());
357
358     // Drop beginFrameAndCommit calls that occur out of sequence. See createBeginFrameAndCommitTaskOnCCThread for
359     // an explanation of how out-of-sequence beginFrameAndCommit tasks can occur.
360     if (sequenceNumber < m_lastExecutedBeginFrameAndCommitSequenceNumber) {
361         TRACE_EVENT("EarlyOut_StaleBeginFrameAndCommit", this, 0);
362         return;
363     }
364     m_lastExecutedBeginFrameAndCommitSequenceNumber = sequenceNumber;
365
366     // FIXME: recreate the context if it was requested by the impl thread
367     {
368         TRACE_EVENT("CCLayerTreeHost::animateAndLayout", this, 0);
369         m_layerTreeHost->animateAndLayout(frameBeginTime);
370     }
371
372     ASSERT(m_lastExecutedBeginFrameAndCommitSequenceNumber == sequenceNumber);
373
374     // Clear the commit flag after animateAndLayout here --- objects that only
375     // layout when painted will trigger another setNeedsCommit inside
376     // updateLayers.
377     m_commitRequested = false;
378
379     m_layerTreeHost->updateLayers();
380
381     {
382         // Blocking call to CCThreadProxy::commitOnCCThread
383         TRACE_EVENT("commit", this, 0);
384         CCCompletionEvent completion;
385         s_ccThread->postTask(createCCThreadTask(this, &CCThreadProxy::commitOnCCThread, AllowCrossThreadAccess(&completion)));
386         completion.wait();
387     }
388
389     m_layerTreeHost->commitComplete();
390
391     if (m_redrawAfterCommit)
392         setNeedsRedraw();
393     m_redrawAfterCommit = false;
394
395     ASSERT(m_lastExecutedBeginFrameAndCommitSequenceNumber == sequenceNumber);
396 }
397
398 void CCThreadProxy::commitOnCCThread(CCCompletionEvent* completion)
399 {
400     TRACE_EVENT("CCThreadProxy::beginFrameAndCommitOnCCThread", this, 0);
401     ASSERT(isImplThread());
402     ASSERT(m_schedulerOnCCThread->commitPending());
403     if (!m_layerTreeHostImpl) {
404         completion->signal();
405         return;
406     }
407     m_layerTreeHostImpl->beginCommit();
408     m_layerTreeHost->commitToOnCCThread(m_layerTreeHostImpl.get());
409     m_layerTreeHostImpl->commitComplete();
410
411     completion->signal();
412
413     m_schedulerOnCCThread->didCommit();
414 }
415
416 void CCThreadProxy::drawLayersAndPresentOnCCThread()
417 {
418     TRACE_EVENT("CCThreadProxy::drawLayersOnCCThread", this, 0);
419     ASSERT(isImplThread());
420     if (!m_layerTreeHostImpl)
421         return;
422
423     drawLayersOnCCThread();
424     m_layerTreeHostImpl->present();
425     m_schedulerOnCCThread->didDraw();
426 }
427
428 void CCThreadProxy::drawLayersOnCCThread()
429 {
430     TRACE_EVENT("CCThreadProxy::drawLayersOnCCThread", this, 0);
431     ASSERT(isImplThread());
432     ASSERT(m_layerTreeHostImpl);
433
434     m_layerTreeHostImpl->drawLayers();
435     ASSERT(!m_layerTreeHostImpl->isContextLost());
436 }
437
438 void CCThreadProxy::initializeImplOnCCThread(CCCompletionEvent* completion)
439 {
440     TRACE_EVENT("CCThreadProxy::initializeImplOnCCThread", this, 0);
441     ASSERT(isImplThread());
442     m_layerTreeHostImpl = m_layerTreeHost->createLayerTreeHostImpl();
443     m_schedulerClientOnCCThread = CCThreadProxySchedulerClient::create(this);
444     m_schedulerOnCCThread = CCScheduler::create(m_schedulerClientOnCCThread.get());
445     completion->signal();
446 }
447
448 void CCThreadProxy::initializeLayerRendererOnCCThread(GraphicsContext3D* contextPtr, CCCompletionEvent* completion, bool* initializeSucceeded, LayerRendererCapabilities* capabilities, int* compositorIdentifier)
449 {
450     TRACE_EVENT("CCThreadProxy::initializeLayerRendererOnCCThread", this, 0);
451     ASSERT(isImplThread());
452     RefPtr<GraphicsContext3D> context(adoptRef(contextPtr));
453     *initializeSucceeded = m_layerTreeHostImpl->initializeLayerRenderer(context);
454     if (*initializeSucceeded)
455         *capabilities = m_layerTreeHostImpl->layerRendererCapabilities();
456
457     m_scrollControllerAdapterOnCCThread = CCThreadProxyScrollControllerAdapter::create(this);
458     m_inputHandlerOnCCThread = CCInputHandler::create(m_scrollControllerAdapterOnCCThread.get());
459     *compositorIdentifier = m_inputHandlerOnCCThread->identifier();
460
461     completion->signal();
462 }
463
464 void CCThreadProxy::layerTreeHostClosedOnCCThread(CCCompletionEvent* completion)
465 {
466     TRACE_EVENT("CCThreadProxy::layerTreeHostClosedOnCCThread", this, 0);
467     ASSERT(isImplThread());
468     m_layerTreeHost->deleteContentsTexturesOnCCThread(m_layerTreeHostImpl->contentsTextureAllocator());
469     m_layerTreeHostImpl.clear();
470     m_inputHandlerOnCCThread.clear();
471     m_scrollControllerAdapterOnCCThread.clear();
472     completion->signal();
473 }
474
475 } // namespace WebCore