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